#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <openssl/des.h>
#include <assert.h>

#include "my_types.h"
#include "utils.h"
#include "finite_state_machine.h"
#include "fy_crypt.h"

#define RECV_BUF_SIZE 128

/**********
 * 选项支持数组
 * 0 - 不支持
 * 1 - 支持
 * init_if_support()用以初始化
 * ********/
bool if_support[255];
bool if_enable[255];

void init_if_support()
{
    if_support[ECHO] = 1;
}

char server_ip[16];     //服务器IPv4地址
int server_port = 1234; //服务器端口m

//检查参数数目及是否为一个合法的ipv4地址
void check_args(int argc, char *argv[])
{
    print_log((char *)"参数检查开始");
    if (argc != 2)
    {
        print_error((char *)"参数应为1个ipv4地址");
        exit(-1);
    }
    char *ip = argv[1];
    if (!check_ip(ip))
    {
        char error[100];
        sprintf(error, "%s不是合法的ip地址", ip);
        print_error(error);
        exit(-1);
    }
    memset(server_ip, 0, sizeof(server_ip));
    memcpy(server_ip, argv[1], strlen(argv[1]));
    print_log((char *)"参数检查完成");
}

sockaddr_in sock_addr; //套接字网络地址
int fd_server_sock;    //套接字

//初始化套接字
void init_socket()
{
    print_log((char *)"初始化网络连接开始");

    sock_addr.sin_family = AF_INET;
    sock_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    sock_addr.sin_port = htons(server_port);

    if ((fd_server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
    {
        print_error((char *)"套接字创建失败");
        exit(-1);
    }

    if (connect(fd_server_sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)))
    {
        print_error((char *)"网络连接失败");
        exit(-1);
    }

    print_log((char *)"初始化网络连接完成");
}

unsigned char public_key[] = "-----BEGIN PUBLIC KEY-----\n\
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApxT0xguRfpLKmKQbpgFV\n\
rWxyJrFU160+PXYUr7OG2nMkDHQqHiMc4fK5qJAdgSRIbqfij2PZ2qkR2RDsfBIN\n\
sIO1IpW1S6rU3Rzf/GcpsB2XBHQDnP0gvydn6B8Pp/XHleWV/2Az0CMcb8BBGaN3\n\
/wakZ5Fbv1Sb3fG9eyw3ggykMZ8KDAkYw/5qMy05/drBwcoVogmW2jtvWZF7pY2E\n\
oUIESXj0Q5350WNUXwXSQbXJZFvyQMhu5U21wPdQ8kUMa6MFhbVP79t4nhDjHIps\n\
tfr2cmAUDd2pgN3neO0g9t6NymMaNG678I5PsLAlFJ37trQlQJtgshv+zJJSowNh\n\
VwIDAQAB\n\
-----END PUBLIC KEY-----";

unsigned char private_key[] = "-----BEGIN PRIVATE KEY-----\n\
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCnFPTGC5F+ksqY\n\
pBumAVWtbHImsVTXrT49dhSvs4bacyQMdCoeIxzh8rmokB2BJEhup+KPY9naqRHZ\n\
EOx8Eg2wg7UilbVLqtTdHN/8ZymwHZcEdAOc/SC/J2foHw+n9ceV5ZX/YDPQIxxv\n\
wEEZo3f/BqRnkVu/VJvd8b17LDeCDKQxnwoMCRjD/mozLTn92sHByhWiCZbaO29Z\n\
kXuljYShQgRJePRDnfnRY1RfBdJBtclkW/JAyG7lTbXA91DyRQxrowWFtU/v23ie\n\
EOMcimy1+vZyYBQN3amA3ed47SD23o3KYxo0brvwjk+wsCUUnfu2tCVAm2CyG/7M\n\
klKjA2FXAgMBAAECggEBAKbtJO+IN0BB3+9IZecghjzRj+pgWOdxyjEVe+1ea2hs\n\
iKN4m2uooP6MxjhGY3PWkBcd3BhuJgVzzMUVR29dihfEPn/jGlISxsByTMWbO+cc\n\
aPil/8Ykj0brU8Bw5+9iepij24xczOcxbQOpDGFVFFnShQaEDynEmkTPdANPVdWy\n\
tjuTgKbXPqeQlfa7MIUwWaVRaiaZPxTBjEUsPwTIVKtT1gElCBamP5UVtuntMVR9\n\
7HG6+c3sqOQ/5/t7ovgylUqBPmKI3aUSS46XcnNX62hhLWPRiNe7NX4S4u00Q4j+\n\
qbRaDF9cLhuLbuKrrVq9fxXAVDnr5hkOBaO9NORP2MECgYEA0fBu3cSF2YxSdhcV\n\
Obws2UkVIWBb0Zo15qjlyG+t9ATPHaCgSZBiKtpu6NtBWzDjbYMHv61Qf4XfZHUc\n\
J+h8M130GzMpwraDTJztlHrI3wFKqSSD6RzlS2h6lInNbVDkeap0mZgIA5CxkhOR\n\
zhnAjq4Tr9USeeHPfBE/hlZ2tmkCgYEAy71fiydn00uRYFolZCS2P5d1GdJ4TwpQ\n\
UTDxP1Guu7bkl/lshB6CnVP87YKYFWg/mIvkwOvuNEart3RpC9cbaurIM1vifWu0\n\
COgGatGSY+aXabOFEd3T1E7Ps1WgiRq/P6MdfuaXjlpJ5MQw71AmkFmoCTfsri4S\n\
XmkMqztH4b8CgYBdA1VbU/KpjA4M2/U/eyuzqTl/bB3CI7y10SbdQv2jG25YBg5+\n\
CUY1DkoNSPcP2/0nS+Jm/faoSTvMWkZ7N/mvGHVKh8R8zDgn/W8VVcEhbIUTo2X+\n\
JhtA6a1Fmjg1sp1HeknmswD582V4/sqesbIqhN2cDZ79+RngMhQfBLfb4QKBgQCN\n\
rRl0halwSDtGmkkoE1NcczDuDOq2ZACoBPWtx1pPlIXvnHW2hhTj3JSkgMzLDhwz\n\
MwyWjzmsxnwAbYXiwumA9tTSyhF8j9m428ginatDpwUhbsGZQ/1axJcwKNoinSPi\n\
18XaCfXX+rcpyrgQola+yGnOR0JheQ4y8q/pnqaEtwKBgDf9v9Qu92PEGngEAXri\n\
mjfLDSN2+FFwomYYHSenQgZSlgtxwkZY3NasPjvq/WoV7ly4zg2IbWrtenqYF2bT\n\
R2p2fyGFPRm0XzPu4y3HqpWLgNlEmaPSSS6rqJ/dHqXoVvlMgVfUMS/mvCsyD96H\n\
zw4o6zcy298IYnpiEdkX2qZR\n\
-----END PRIVATE KEY-----";

uchar key[9];
uchar encrypted_key[257];
void process_crypt()
{
    //memcpy(key, "12345678", 8);
    rand_ch_buf(key, 8);
    RSA_public_encrypt(key, 8, encrypted_key, public_key);
    send(fd_server_sock, encrypted_key, 256, 0);
}

void negotiate()
{
}

void process_send()
{
    print_log((char *)"process_send开始");
    uchar ch;
    uchar ch_buf[8];
    uchar encrypted_ch[8];
    while (1)
    {

        if (read(STDIN_FILENO, &ch, 1) > 0)
        {
            ch_buf[0] = ch;
            DES_encrypt(ch_buf, encrypted_ch, key);
            send(fd_server_sock, encrypted_ch, 8, 0); //stdin --> server_sock
        }
    }
    print_log((char *)"process_send结束");
}

void process_data(uchar ch)
{
    write(STDOUT_FILENO, &ch, 1);
}

void deal_client_ECHO(uchar verb)
{
}

void deal_client_SGA(uchar verb)
{
}

void deal_client_TERMTYPE(uchar verb)
{
}

void deal_client_ENVIRON(uchar verb)
{
}

void deal_client_LINEMODE(uchar verb)
{
}

void deal_client_NAWS(uchar verb)
{
}

void deal_client_STATUS(uchar verb)
{
}

void deal_client_TSPEED(uchar verb)
{
}

void deal_client_LFLOW(uchar verb)
{
}

void send_client_pass(uchar verb, uchar option)
{
    uchar sendbuf[3];
    sendbuf[0] = IAC;
    sendbuf[1] = verb;
    sendbuf[2] = option;
    send(fd_server_sock, (char *)sendbuf, 3, 0);
}

void send_server_term_type()
{
}

finite_state_machine_t finite_state_machine;
void init_finite_state_machine()
{
    finite_state_machine_t &fsm = finite_state_machine;
    fsm.process_data = process_data;
    fsm.deal_ECHO = deal_client_ECHO;
    fsm.deal_SGA = deal_client_SGA;
    fsm.deal_TERMTYPE = deal_client_TERMTYPE;
    fsm.deal_ENVIRON = deal_client_ENVIRON;
    fsm.deal_LINEMODE = deal_client_LINEMODE;
    fsm.deal_NAWS = deal_client_NAWS;
    fsm.deal_STATUS = deal_client_STATUS;
    fsm.deal_TSPEED = deal_client_TSPEED;
    fsm.deal_LFLOW = deal_client_LFLOW;
    fsm.send_pass = send_client_pass;
    fsm.send_term_type = send_server_term_type;
}

void process_recv()
{
    print_log((char *)"process_recv开始");
    uchar ch;
    uchar ch_buf[8];
    uchar encrypted_ch[8];
    while (1)
    {
        if (recv(fd_server_sock, encrypted_ch, 8, 0) > 0)
        {
            DES_decrypt(encrypted_ch, ch_buf, key);
            ch = ch_buf[0];
            finite_state_machine(ch);
        }
    }
    print_log((char *)"process_recv结束");
}

int client()
{
    print_log((char *)"执行客户端开始");
    init_if_support();
    system("stty -echo");
    system("stty -icanon");
    init_socket(); //初始化网络连接
    process_crypt();
    negotiate(); //协议协商
    init_finite_state_machine();
    if (fork())
        process_recv();
    else
        process_send();
    close(fd_server_sock);
    print_log((char *)"执行客户端完成");
    return 0;
}

int main(int argc, char *argv[])
{
    check_args(argc, argv); //参数检查
    return client();        //执行客户端
}